package cn.mmanager.framework.interceptor;

import cn.mmanager.common.constant.UserConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.function.Predicate;

/**
 * 登录拦截器
 * @author NicholasLD
 * Login Interceptor
 * @createTime 2023/4/3 10:55
 */
public class LoginInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
    private static final String LOGIN_URI = "/login";
    private static final String DO_LOGIN_URI = "/dologin";
    private static final String LOGOUT_URI = "/logout";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        logger.info("Detected request：{}", request.getRequestURI());
        return handleRequest(request, response);
    }

    /**
     * 处理请求
     * Handle the request
     */
    private boolean handleRequest(HttpServletRequest request, HttpServletResponse response) {
        RequestHandler handler = RequestHandler.resolve(request);
        return handler != null && handler.handle(this, request, response);
    }

    /**
     * 登录请求处理器
     * Login request handler
     */
    private boolean handleLogin(HttpServletRequest request, HttpServletResponse response) {
        return redirectToHomeIfLoggedIn(request, response);
    }

    /**
     * 登录请求处理器（POST请求）
     * Login request handler (POST request)
     */
    private boolean handleDoLogin(HttpServletRequest request, HttpServletResponse response) {
        return true; // 假设/dologin是POST请求，应始终被处理
    }

    /**
     * 注销请求处理器
     * Logout request handler
     */
    private boolean handleLogout(HttpServletRequest request, HttpServletResponse response) {
        return redirectToLoginIfNotLoggedIn(request, response);
    }

    /**
     * 普通请求处理器
     * Normal request handler
     */
    private boolean handleNormalRequest(HttpServletRequest request, HttpServletResponse response) {
        return redirectToLoginWithRedirectParamIfNotLoggedIn(request, response);
    }

    /**
     * 如果用户已登录，则重定向到主页
     * Redirect to home if user is logged in
     */
    private boolean redirectToHomeIfLoggedIn(HttpServletRequest request, HttpServletResponse response) {
        return checkSessionAndRedirect(request, response, "/");
    }

    /**
     * 如果用户未登录，则重定向到登录页
     * Redirect to login if user is not logged in
     */
    private boolean redirectToLoginIfNotLoggedIn(HttpServletRequest request, HttpServletResponse response) {
        return checkSessionOrRedirect(request, response, LOGIN_URI);
    }

    /**
     * 如果用户未登录，并且带有重定向参数，则重定向到登录页
     * Redirect to login with redirect param if user is not logged in
     */
    private boolean redirectToLoginWithRedirectParamIfNotLoggedIn(HttpServletRequest request, HttpServletResponse response) {
        return checkSessionOrRedirect(request, response, LOGIN_URI + "?redirect=" + request.getRequestURI());
    }

    /**
     * 检查会话并重定向
     * Check session and redirect
     */
    private boolean checkSessionAndRedirect(HttpServletRequest request, HttpServletResponse response, String redirectUri) {
        try {
            HttpSession session = request.getSession(false); // 不创建新会话
            if (session != null && session.getAttribute(UserConstants.USER_SESSION) != null) {
                logger.info("[Login] User is logged in, redirecting to the homepage");
                response.sendRedirect(redirectUri);
                return false;
            }
        } catch (IOException e) {
            logger.error("IO exception occurred during redirection", e);
        }
        return true;
    }

    /**
     * 检查会话或重定向
     * Check session or redirect
     */
    private boolean checkSessionOrRedirect(HttpServletRequest request, HttpServletResponse response, String redirectUri) {
        try {
            HttpSession session = request.getSession(false); // 不创建新会话
            if (session == null || session.getAttribute(UserConstants.USER_SESSION) == null) {
                logger.info("User is not logged in, redirecting to the login page");
                response.sendRedirect(redirectUri);
                return false;
            }
        } catch (IOException e) {
            logger.error("IO exception occurred during redirection", e);
        }
        return true;
    }

    /**
     * 请求处理器
     * Request Handler
     */
    enum RequestHandler {
        LOGIN(request -> LOGIN_URI.equals(request.getRequestURI())),
        DO_LOGIN(request -> DO_LOGIN_URI.equals(request.getRequestURI())),
        LOGOUT(request -> LOGOUT_URI.equals(request.getRequestURI())),
        NORMAL(request -> true); // 默认处理器

        private final Predicate<HttpServletRequest> predicate;

        RequestHandler(Predicate<HttpServletRequest> predicate) {
            this.predicate = predicate;
        }

        public boolean handle(LoginInterceptor interceptor, HttpServletRequest request, HttpServletResponse response) {
            switch (this) {
                case LOGIN:
                    return interceptor.handleLogin(request, response);
                case DO_LOGIN:
                    return interceptor.handleDoLogin(request, response);
                case LOGOUT:
                    return interceptor.handleLogout(request, response);
                case NORMAL:
                    return interceptor.handleNormalRequest(request, response);
                default:
                    return false;
            }
        }

        public static RequestHandler resolve(HttpServletRequest request) {
            for (RequestHandler handler : values()) {
                if (handler.predicate.test(request)) {
                    return handler;
                }
            }
            return NORMAL;
        }
    }
}